#pragma once

#include "include/types.h"

#define E820MAX 32 /* Number of E820 records */
#define E820_RAM 1 /* The E820 record of type RAM represents the available physical memory area */
#define MAX_PAGES (1024 * 1024) /* 1M units (capable of labeling 4GB of memory) used to label physical page usage: 0|1 */
#define KERNEL_PAGE_NUM (1024 * 16) /* 16K physical pages(64MB kernel image, = 32 * 512 Item * 4KB) mapped from 32 LV-1 page tables */
#define PAGE_SIZE 4096 /* Physical page size 4KB */
#define VA(pa) ((void*)((unsigned long)(pa) + 0xffff888000000000)) /* Linear mapping: converting physical addresses to virtual addresses */
#define TASK0_PML4 0x30000 /* 4th level root page table physical address */

extern unsigned long mem_size; // Maximum memory size
extern uint8_t pages[MAX_PAGES]; // Page occupancy array

struct e820entry {
  uint64_t addr; // (8B) Physical memory start address
  uint64_t size; // (8B) Physical memory length
  uint32_t type; // (4B) Physical memory type: RAM(1)|..
} __attribute__((packed)); // Inform the gcc compiler not to align structural variables according to cache lines,
                           // but to allocate them according to actual nearest neighbors
struct e820map {
  uint32_t nr_entry; // (4B) record num
  struct e820entry map[E820MAX]; // record array
};

void mm_init();
void map_range(unsigned long pml4_pa, unsigned long from_va, unsigned long to_pa, char us, long npage);
unsigned long alloc_page();
void free_page(uint64_t addr);
void* malloc(int size);
void free(void* va);